package com.tianquan.miracle.util;/**
 * @author starsea
 * @date 2024-09-29 下午12:17
 */

import com.tianquan.miracle.annotation.Component;
import com.tianquan.miracle.annotation.Configuration;
import com.tianquan.miracle.annotation.MiracleFastApplication;
import com.tianquan.miracle.aop.After;
import com.tianquan.miracle.aop.AopEntity;
import com.tianquan.miracle.aop.Around;
import com.tianquan.miracle.aop.Before;
import com.tianquan.miracle.context.ApplicationContext;

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

/**
 * @BelongsProject: uploaddemo
 * @BelongsPackage: com.tianquan.miracle.util
 * @Author: tianquan
 * @CreateTime: 2024-09-29  12:17
 * @Description: 框架工具类
 * @Version: 1.0
 */
public class MiracleUtils {

    private static ApplicationContext applicationContext;

    private static final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

    public static void init(ApplicationContext applicationContext) {
        MiracleUtils.applicationContext = applicationContext;
    }

    public static ClassLoader getClassLoader() {
        return classLoader;
    }

    /**
     * @description: 根据class生成beanName
     * @author: tianquan
     * @date: 2024/10/19 下午10:06
     * @param: [clazz]
     * @return: java.lang.String
     **/
    public static String createBeanName(Class<?> clazz) {
        if (clazz.getName().contains("$")) return clazz.getSimpleName().toLowerCase();
        String name = clazz.getName();
        String beanName = name.substring(name.lastIndexOf(".") + 1);
        return beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
    }

    /**
     * @description: 判断类上是否有annotation注解类对象，有就返回
     * @author: tianquan
     * @date: 2024/10/19 下午10:04
     * @param: [clazz, annotation]
     * @return: T
     **/
    public static <T> T isExist(Class<?> clazz, Class<T> annotation) {
        T object = null;
        isExist(clazz, annotation, object);
        return (T) object;
    }

    private static <T> void isExist(Class<?> clazz, Class<T> annotation, Object object) {
        Annotation[] annotations = clazz.getAnnotations();
        if (annotations == null) return;
        for (Annotation a : annotations) {
            isExist(a.getClass(), annotation, object);
            if (a.getClass() == annotation) {
                object = a;
                return;
            }
        }
    }

    /**
     * @description: 需要扫描成bean的注解
     * @author: tianquan
     * @date: 2024/10/19 下午10:06
     * @param: [clazz]
     * @return: java.lang.String
     **/
    public static String sanComponent(Class<?> clazz) {
        Component component = clazz.getAnnotation(Component.class);
        if (component != null) {
            String value = component.value();
            if (value.isEmpty()) {
                return createBeanName(clazz);
            }
            return value;
        }
        Configuration configuration = clazz.getAnnotation(Configuration.class);
        if (configuration != null) {
            return MiracleUtils.createBeanName(clazz);
        }
        MiracleFastApplication miracleFastApplication = clazz.getAnnotation(MiracleFastApplication.class);
        if (miracleFastApplication != null) {
            return MiracleUtils.createBeanName(clazz);
        }
        return null;
    }

    /**
     * @description: 获取application.properties文件
     * @author: tianquan
     * @date: 2024/10/19 下午10:03
     * @param: []
     * @return: java.util.Properties
     **/
    public static Properties getProperties() {
        Properties properties = new Properties();
        InputStream inputStream = null;
        try {
            inputStream = classLoader.getResourceAsStream("application.properties");
            properties.load(inputStream);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return properties;
    }

    /**
     * @description: 判断当前类是否是目标类的子类
     * @author: tianquan
     * @date: 2024/10/19 下午10:02
     * @param: [clazz, parentClass]
     * @return: boolean
     **/
    public static boolean isDescendantClass(Class<?> clazz, Class<?> parentClass) {
        if (clazz == null) {
            return false;
        }
        return clazz.equals(parentClass) || isDescendantClass(clazz.getSuperclass(), parentClass);
    }

    /**
     * @description: 判断当前类是否与目标类或接口有关联
     * @author: tianquan
     * @date: 2024/10/19 下午10:02
     * @param: [clazz, targetClassOrInterface]
     * @return: boolean
     **/
    public static boolean isRelatedTo(Class<?> clazz, Class<?> targetClassOrInterface) {
        if (clazz == null) {
            return false;
        }
        if (clazz.equals(targetClassOrInterface)) {
            return true;
        }
        List<Class<?>> interfaces = Arrays.asList(clazz.getInterfaces());
        for (Class<?> anInterface : interfaces) {
            if (isRelatedTo(anInterface, targetClassOrInterface)) {
                return true;
            }
        }
        return isRelatedTo(clazz.getSuperclass(), targetClassOrInterface);
    }

    public static Object getBean(String beanName) {
        return applicationContext.getBean(beanName);
    }

    public static Object getBean(Class<?> clazz) {
        return applicationContext.getBean(clazz);
    }

    public static void registerBean(String name, Object bean) {
        applicationContext.registerBean(name, bean);
    }

    public static void cheekAnnotation(AopEntity aopEntity, String methodName) {
        Method beforeMethod = aopEntity.getBeforeMethod();
        Method afterMethod = aopEntity.getAfterMethod();
        Method aroundMethod = aopEntity.getAroundMethod();
        if (beforeMethod != null) MiracleUtils.annotationException(beforeMethod.getAnnotation(Before.class), methodName);
        if (afterMethod != null) MiracleUtils.annotationException(afterMethod.getAnnotation(After.class), methodName);
        if (aroundMethod != null) MiracleUtils.annotationException(aroundMethod.getAnnotation(Around.class), methodName);
    }

    public static void annotationException(Annotation annotation, String methodName) {
        Object invoke = null;
        try {
            invoke = annotation.getClass().getMethod("value").invoke(annotation);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (invoke == null) throw new RuntimeException("The value of the annotation cannot be empty");
        if (!invoke.toString().replace("()", "").equals(methodName))
            throw new RuntimeException("The tangent method name is different from the tangent method name");
    }

    public static <T extends Annotation> T parseMethod(Method method, Class<T> annotation) {
        return method.getAnnotation(annotation);
    }

}
